package cn.cmft.jc.utils;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidPooledConnection;
import com.alibaba.druid.proxy.jdbc.PreparedStatementProxy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

public class DruidClient implements Serializable {
    private static final Logger logger = LoggerFactory.getLogger(DruidClient.class);
    private final String driver;
    private final String url;
    private final String username;
    private final String password;
    private DruidDataSource dataSource;

    public DruidClient(String driver, String url, String username, String password) {
        this.driver = driver;
        this.url = url;
        this.username = username;
        this.password = password;
    }


    /**
     * @param sql    查询语句，例如：SELECT * FROM your_table WHERE condition
     * @param mapper 结果映射器，用于将ResultSet中的数据转换为目标类型
     * @param params 查询参数（可选），如果查询语句中有占位符，用于设置对应的值
     * @param <T>    返回结果的类型参数
     * @return 查询结果的列表，列表元素类型为<T>
     * @throws SQLException
    */
    public<T> List<T> query(String sql, ResultSetMapper<T> mapper,Object...params) throws SQLException {
        List<T> resultList = new ArrayList<>();
        try (DruidPooledConnection connection = dataSource.getConnection();
             PreparedStatement statement = connection.prepareStatement(sql)){
            //判断是否有参数传入，如果有则设置到PreparedStatement中
            if (!Objects.isNull(params) && params.length > 0){
                for (int i = 0; i < params.length; i++) {
                    statement.setObject(i+1, params[i]);
                }
            }
            logger.info(MessageFormat.format("执行sql:\n{0}", statement));
            // 执行查询
            try (ResultSet resultSet = statement.executeQuery()){
                while (resultSet.next()){
                    T result = mapper.map(resultSet);
                    resultList.add(result);
                }
            }
        }
        return resultList;
    }

    public void open() {
        if (Objects.isNull(dataSource)) {
            dataSource = new DruidDataSource();
            dataSource.setDriverClassName(driver);
            dataSource.setUrl(url);
            dataSource.setUsername(username);
            dataSource.setPassword(password);
            dataSource.setValidationQuery("select 1");
            dataSource.setMaxWaitThreadCount(10);
            dataSource.setMaxActive(5);
        }
    }

    public void close(){
        Optional<DruidDataSource> dataSourceOp = Optional.ofNullable(this.dataSource);
        if (dataSourceOp.isPresent()){
            this.dataSource.close();
        }
    }

    @FunctionalInterface
    public interface ResultSetMapper<T>{
        T map(ResultSet resultSet) throws SQLException;
    }
}
